//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#include "CheckPatternInFastaFile.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <zlib.h>

#include <fstream>
#include <iostream>
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
using namespace std;
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#define MAX_SIZE 500000
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
CheckPatternInFastaFile::CheckPatternInFastaFile () {

  this->filenamePatterns = new String ();
  this->filenameFasta    = new String ();
  this->filenameOut      = new String ();
  this->patterns         = new TListE <String> ();
  this->sequences        = new ListFastaData ();
  this->toString         = new String ();

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
CheckPatternInFastaFile::CheckPatternInFastaFile (const CheckPatternInFastaFile& checkPatternInFastaFile) {

  this->filenamePatterns = new String (checkPatternInFastaFile.filenamePatterns);
  this->filenameFasta    = new String (checkPatternInFastaFile.filenameFasta);
  this->filenameOut      = new String (checkPatternInFastaFile.filenameOut);
  this->patterns         = new TListE <String> (checkPatternInFastaFile.patterns);
  this->sequences        = new ListFastaData (checkPatternInFastaFile.sequences);
  this->toString         = new String (checkPatternInFastaFile.toString);

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
CheckPatternInFastaFile::CheckPatternInFastaFile (const CheckPatternInFastaFile* checkPatternInFastaFile) {

  this->filenamePatterns = new String (checkPatternInFastaFile->filenamePatterns);
  this->filenameFasta    = new String (checkPatternInFastaFile->filenameFasta);
  this->filenameOut      = new String (checkPatternInFastaFile->filenameOut);
  this->patterns         = new TListE <String> (checkPatternInFastaFile->patterns);
  this->sequences        = new ListFastaData (checkPatternInFastaFile->sequences);
  this->toString         = new String (checkPatternInFastaFile->toString);

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
CheckPatternInFastaFile::~CheckPatternInFastaFile () {

  if (this->filenamePatterns) delete this->filenamePatterns;
  if (this->filenameFasta)    delete this->filenameFasta;
  if (this->filenameOut)      delete this->filenameOut;
  if (this->patterns)         delete this->patterns;
  if (this->sequences)        delete this->sequences;
  if (this->toString)         delete this->toString;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void CheckPatternInFastaFile::FilenamePatterns (String* filenamePatterns) {

  if (filenamePatterns)
    *(this->filenamePatterns) = *filenamePatterns;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void CheckPatternInFastaFile::FilenameFasta (String* filenameFasta) {

  if (filenameFasta)
    *(this->filenameFasta) = *filenameFasta;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void CheckPatternInFastaFile::FilenameOut (String* filenameOut) {

  if (filenameOut)
    *(this->filenameOut) = *filenameOut;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void CheckPatternInFastaFile::Patterns (TListE <String>* patterns) {

  if (patterns)
    *(this->patterns) = *patterns;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void CheckPatternInFastaFile::Sequences (ListFastaData* sequences) {

  if (sequences)
    *(this->sequences) = *sequences;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* CheckPatternInFastaFile::FilenamePatterns (void) {

  return this->filenamePatterns;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* CheckPatternInFastaFile::FilenameFasta (void) {

  return this->filenameFasta;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* CheckPatternInFastaFile::FilenameOut (void) {

  return this->filenameOut;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
TListE <String>* CheckPatternInFastaFile::Patterns (void) {

  return this->patterns;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ListFastaData* CheckPatternInFastaFile::Sequences (void) {

  return this->sequences;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool CheckPatternInFastaFile::LoadData (void) {

  if (!this->filenameFasta    || !this->filenameFasta->Length()    ||
      !this->filenamePatterns || !this->filenamePatterns->Length())
    return false;

  this->sequences->FilenameIn(this->filenameFasta);

  if (!this->sequences->LoadData())
    return false;

  bool isGZFile = (this->filenamePatterns->Contain("gz"))?1:0;

  fstream file;
  gzFile  zipFile;

  char    buffer [MAX_SIZE + 1];
  
  if (isGZFile) zipFile = gzopen (this->filenamePatterns->Out(), "rb9");
  else          file.open (this->filenamePatterns->Out(), fstream::in);

  while (!((isGZFile)?gzeof(zipFile):file.eof())) {
    
    if (isGZFile) gzgets(zipFile, buffer, MAX_SIZE);
    else          file.getline(buffer, MAX_SIZE);
    
    if (!strlen(buffer)) continue;
    
    this->patterns->Add(new String(buffer));
    
  }

  if (isGZFile) gzclose(zipFile);
  else          file.close();

  return true;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool CheckPatternInFastaFile::OutSequenceWithPatterns (void) {

  if (!this->patterns    || !this->patterns->Length()          ||
      !this->sequences   || !this->sequences->Data()->Length() ||
      !this->filenameOut || !this->filenameOut->Length())
    return false;

  ofstream file (this->filenameOut->Out());

  if (!file.is_open()) return false;

  SearchPrositePattern* searchPrositePattern = new SearchPrositePattern ();

  this->sequences->Data()->SetInitial();
  while (this->sequences->Data()->SetNext()) {
    
    FastaData* currentFastaData = this->sequences->Data()->GetCurrent();
    bool       containPattern   = false;
    
    this->patterns->SetInitial();
    while (this->patterns->SetNext()) {
      
      String* sequence = new String ();
      
      sequence->In("");
      
      for (int i = 0; i < currentFastaData->Sequence()->Length(); i++)
        if (currentFastaData->Sequence()->Out()[i] != '-')
          sequence->Add(currentFastaData->Sequence()->Out()[i]);
      
      searchPrositePattern->SearchPattern(sequence, this->patterns->GetCurrent());

      if (sequence) delete sequence;
      
      if (searchPrositePattern->Segments()->Length()) {
        containPattern = true;
        break;
      }
      
    }
    
    if (containPattern)
      file << currentFastaData->ToString()->Out() << endl;
    
  }

  file.close();

  if (searchPrositePattern) delete searchPrositePattern;

  return true;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool CheckPatternInFastaFile::OutSequenceWithoutPatterns (void) {

  if (!this->patterns    || !this->patterns->Length()          ||
      !this->sequences   || !this->sequences->Data()->Length() ||
      !this->filenameOut || !this->filenameOut->Length())
    return false;

  ofstream file (this->filenameOut->Out());

  if (!file.is_open()) return false;

  SearchPrositePattern* searchPrositePattern = new SearchPrositePattern ();

  this->sequences->Data()->SetInitial();
  while (this->sequences->Data()->SetNext()) {
    
    FastaData* currentFastaData = this->sequences->Data()->GetCurrent();
    bool       containPattern   = false;
    
    this->patterns->SetInitial();
    while (this->patterns->SetNext()) {
      
      String* sequence = new String ();
      
      sequence->In("");
      
      for (int i = 0; i < currentFastaData->Sequence()->Length(); i++)
        if (currentFastaData->Sequence()->Out()[i] != '-')
          sequence->Add(currentFastaData->Sequence()->Out()[i]);
      
      searchPrositePattern->SearchPattern(sequence, this->patterns->GetCurrent());

      if (sequence) delete sequence;
      
      if (searchPrositePattern->Segments()->Length()) {
        containPattern = true;
        break;
      }
      
    }
    
    if (!containPattern)
      file << currentFastaData->ToString()->Out() << endl;
    
  }

  file.close();

  if (searchPrositePattern) delete searchPrositePattern;

  return true;


}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* CheckPatternInFastaFile::ToString (void) {
  
  this->toString->In("");
  
  return this->toString;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
CheckPatternInFastaFile CheckPatternInFastaFile::operator= (const CheckPatternInFastaFile& checkPatternInFastaFile) {

  *(this->filenamePatterns) = *(checkPatternInFastaFile.filenamePatterns);
  *(this->filenameFasta)    = *(checkPatternInFastaFile.filenameFasta);
  *(this->filenameOut)      = *(checkPatternInFastaFile.filenameOut);
  *(this->patterns)         = *(checkPatternInFastaFile.patterns);
  *(this->sequences)        = *(checkPatternInFastaFile.sequences);
  *(this->toString)         = *(checkPatternInFastaFile.toString);

  return *this;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
